﻿using Shop.Model.DB;
using Shop.Model.Stock;
using Shop.RemoteModel;
using SqlSugar;
using WeDonekRpc.Helper;
using WeDonekRpc.Helper.IdGenerator;
using WeDonekRpc.SqlSugar;

namespace Shop.Repository.lmpl
{
    internal class GoodsStockRepository : ShopBaseRepository<DBGoodsStock, long>, IGoodsStockRepository
    {
        public GoodsStockRepository (ISqlClientFactory factory) : base(factory)
        {
        }
        public bool AddStock (StockAdd add, long verId)
        {
            long id = IdentityHelper.CreateId();
            DBGoodsStockLog log = new DBGoodsStockLog
            {
                AddTime = DateTime.Now,
                GoodsId = add.GoodsId,
                Id = id,
                UserId = add.UserId,
                LogType = StockLogType.入库,
                UserType = "emp",
                NewVer = id,
                OldVer = verId,
                SkuId = add.SkuId,
                Stock = add.Stock,
            };
            using (ILocalTransaction tran = base.ApplyTran())
            {
                if (!base.Update(a => new DBGoodsStock
                {
                    CurStock = a.CurStock + add.Stock,
                    Version = id
                }, a => a.SkuId == add.SkuId && a.Version == verId))
                {
                    return false;
                }
                base.Insert<DBGoodsStockLog>(log);
                tran.Commit();
            }
            return true;
        }
        public void InitStock (long goodsId, long userId, Dictionary<long, int> stock)
        {
            DateTime now = DateTime.Now;
            DBGoodsStockLog[] logs = stock.ConvertAll(c => new DBGoodsStockLog
            {
                Id = IdentityHelper.CreateId(),
                UserId = userId,
                SkuId = c.Key,
                GoodsId = goodsId,
                LogType = StockLogType.初始化,
                UserType = "emp",
                OldVer = 0,
                NewVer = 0,
                Stock = c.Value,
                AddTime = now,
            });
            List<DBGoodsStock> adds = stock.Select(a => new DBGoodsStock
            {
                GoodsId = goodsId,
                CurStock = a.Value,
                LastOutTime = null,
                LockStock = 0,
                SkuId = a.Key,
                OutStock = 0,
                Version = 0
            }).ToList();
            using (ILocalTransaction tran = base.ApplyTran())
            {
                if (base.Storageable(adds).ExecuteCommand() < 0)
                {
                    throw new ErrorException("shop.goods.stock.init.error");
                }
                base.Insert<DBGoodsStockLog>(logs);
                tran.Commit();
            }
        }
        public Dictionary<long, int> GetStocks (long goodsId)
        {
            return base.Gets(a => a.GoodsId == goodsId, a => new
            {
                a.SkuId,
                a.CurStock
            }).ToDictionary(a => a.SkuId, a => a.CurStock);
        }
        public Result[] GetStocks<Result> (long[] goodsId) where Result : class, new()
        {
            return base.Gets<Result>(a => goodsId.Contains(a.GoodsId));
        }
        public void LockStock (Dictionary<long, int> set)
        {
            if (set.Count == 1)
            {
                KeyValuePair<long, int> i = set.First();
                if (!base.Update(a => new DBGoodsStock
                {
                    CurStock = a.CurStock - i.Value,
                    LastOutTime = DateTime.Now,
                    LockStock = a.LockStock + i.Value,
                }, a => a.SkuId == i.Key && a.CurStock >= i.Value))
                {
                    throw new ErrorException("shop.goods.stock.shortage");
                }
                return;
            }
            using (ILocalTransaction tran = base.ApplyTran())
            {
                foreach (KeyValuePair<long, int> i in set)
                {
                    if (!base.Update(a => new DBGoodsStock
                    {
                        CurStock = a.CurStock - i.Value,
                        LastOutTime = DateTime.Now,
                        LockStock = a.LockStock + i.Value,
                    }, a => a.SkuId == i.Key && a.CurStock >= i.Value))
                    {
                        throw new ErrorException("shop.goods.stock.shortage");
                    }
                }
                tran.Commit();
            }
        }
    }
}
